import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class FigureInlayCombination {

	private int playerLevel;
	
	private int stoneLevel;
	
	/**
	 * 不败的镶嵌组合（胜利或者平手）
	 */
	private List<StoneCombination> undefeatedCombinationList = new ArrayList<StoneCombination>();
	/**
	 * 胜利的镶嵌组合
	 */
	private List<StoneCombination> winCombinationList = new ArrayList<StoneCombination>();
	/**
	 * 平局的镶嵌组合
	 */
	private List<StoneCombination> drawCombinationList = new ArrayList<StoneCombination>();
	/**
	 * 失败的镶嵌组合
	 */
	private List<StoneCombination> loseCombinationList = new ArrayList<StoneCombination>();
	/**
	 * 所有镶嵌组合
	 */
	private List<StoneCombination> allCombinationList = new ArrayList<StoneCombination>();
	
	/**
	 * Map<不败组合, 优势次数>
	 */
	private Map<StoneCombination, Integer> undefeatedCombinationMap = new HashMap<StoneCombination, Integer>();
	
	public FigureInlayCombination(int playerLevel, int stoneLevel) {
		this.setPlayerLevel(playerLevel);
		this.setStoneLevel(stoneLevel);
	}
	
	/**
	 * 计算所有的组合
	 * @param combinationList
	 */
	public void figureAllCombinationList() {
		for(int attackStoneNumber = 0; attackStoneNumber <= Constant.TOTAL_HOLE_NUMBER; ++attackStoneNumber) {
			for(int defenseStoneNumber = 0; defenseStoneNumber <= Constant.TOTAL_HOLE_NUMBER; ++defenseStoneNumber) {
				for(int hpStoneNumber = 0; hpStoneNumber <= Constant.TOTAL_HOLE_NUMBER; ++hpStoneNumber) {
					if(attackStoneNumber + defenseStoneNumber + hpStoneNumber == Constant.TOTAL_HOLE_NUMBER){
						allCombinationList.add(new StoneCombination(attackStoneNumber, defenseStoneNumber, hpStoneNumber));
					}
				}
			}
		}
	}
	
	/**
	 * 通过模拟战斗，选出胜利或打平的候选组合
	 * @param allCombinationList
	 */
	public void siftOutCombination() {
		for(int i = 0; i < allCombinationList.size(); ++i) {
			for(int j = i + 1 ; j < allCombinationList.size(); ++j) {
				int result = simulteFightResult(allCombinationList.get(i), allCombinationList.get(j));
				if(result == Constant.FORMER_WIN_COMBINATION) {
					addLoseCombination(allCombinationList.get(j));
				}
				else if(result == Constant.LATER_WIN_COMBINATION) {
					addLoseCombination(allCombinationList.get(i));
				}
				else {
					if(result == Constant.FORMER_BETTER_COMBINATION) {
						increaseCombinationNumber(allCombinationList.get(i));
					}
					else if(result == Constant.LATER_BETTER_COMBINATION) {
						increaseCombinationNumber(allCombinationList.get(j));
					}
					addDrawCombination(allCombinationList.get(i));
					addDrawCombination(allCombinationList.get(j));
				}
			}
		}
		
		// 过滤出win和undefeated的combination
		// 一定要先过滤出undefeated的再过滤win的，因为win的要根据undefeated的来过滤
		undefeatedCombinationFilter();
		winCombinationFilter();
		
		// 最后才计算各个不败组合的优势次数
		optimalUndefeatedCombinationFilter();
		
	}
	
	/**
	 * 模拟战斗，得出结果
	 */
	private int simulteFightResult(StoneCombination formerCombination, StoneCombination laterCombination) {
		int formerTotalAttack =  Define.getOriginalState(playerLevel).getAttack()  + formerCombination.getAttackStoneNumber()  * Define.getAttackStoneValue(stoneLevel);
		int formerTotalDefense = Define.getOriginalState(playerLevel).getDefense() + formerCombination.getDefenseStoneNumber() * Define.getDefenseStoneValue(stoneLevel);
		int formerTotalHp =      Define.getOriginalState(playerLevel).getHp()      + formerCombination.getHpStoneNumber()      * Define.getHpStoneValue(stoneLevel);
		
		int laterTotalAttack =   Define.getOriginalState(playerLevel).getAttack()  + laterCombination.getAttackStoneNumber()   * Define.getAttackStoneValue(stoneLevel);
		int laterTotalDefense =  Define.getOriginalState(playerLevel).getDefense() + laterCombination.getDefenseStoneNumber()  * Define.getDefenseStoneValue(stoneLevel);
		int laterTotalHp =       Define.getOriginalState(playerLevel).getHp()      + laterCombination.getHpStoneNumber()       * Define.getHpStoneValue(stoneLevel);
		
		int formerDamage = Constant.figureDamage(formerTotalAttack, laterTotalDefense, laterTotalAttack);
		int laterDamage = Constant.figureDamage(laterTotalAttack, formerTotalDefense, formerTotalAttack);
		while(formerTotalHp > 0 && laterTotalHp > 0) {
			formerTotalHp -= laterDamage;
			laterTotalHp -= formerDamage;
		}
		if(formerTotalHp > 0) {
			return Constant.FORMER_WIN_COMBINATION;
		}
		else if(laterTotalHp > 0) {
			return Constant.LATER_WIN_COMBINATION;
		}
		else {
			if((laterTotalHp / formerDamage) < (formerTotalHp / laterDamage)) {
				return Constant.FORMER_BETTER_COMBINATION;
			}
			else {
				return Constant.LATER_BETTER_COMBINATION;
			}
		}
	}
	private void optimalUndefeatedCombinationFilter() {
		for(int i = 0; i < loseCombinationList.size(); ++i) {
			StoneCombination c = loseCombinationList.get(i);
			Integer num = undefeatedCombinationMap.get(c);
			if(num != null) {
				undefeatedCombinationMap.remove(c);
			}
		}
	}
	
	private void undefeatedCombinationFilter() {
		for(int index = 0; index < allCombinationList.size(); ++index) {
			addUndefeatedCombination(allCombinationList.get(index));
		}
		Iterator<StoneCombination> i = undefeatedCombinationList.iterator();
		while(i.hasNext()) {
			StoneCombination c = i.next();
			for(int n = 0; n < loseCombinationList.size(); ++n) {
				if(c.equals(loseCombinationList.get(n))) {
					i.remove();
				}
			}
		}
	}
	private void winCombinationFilter() {
		for(int index = 0; index < undefeatedCombinationList.size(); ++index) {
			addWinCombination(undefeatedCombinationList.get(index));
		}
		Iterator<StoneCombination> i = winCombinationList.iterator();
		while(i.hasNext()) {
			StoneCombination c = i.next();
			for(int n = 0; n < drawCombinationList.size(); ++n) {
				if(c.equals(drawCombinationList.get(n))) {
					i.remove();
				}
			}
		}
	}
	
	
	
	public void printAllCombinations() {
		System.out.println("所有组合：");
		if(allCombinationList.size() == 0) {
			System.out.println("无" + "\n");
		}
		for(int i = 0; i < allCombinationList.size(); ++i) {
			StoneCombination combination = allCombinationList.get(i);
			printCombination(combination);
		}
	}
	public void printAllCombinationsSize() {
		System.out.println("所有组合个数：" + allCombinationList.size());
	}
	
	public void printWinCombinations() {
		System.out.println("胜利组合：");
		if(winCombinationList.size() == 0) {
			System.out.println("无" + "\n");
		}
		for(int i = 0; i < winCombinationList.size(); ++i) {
			StoneCombination combination = winCombinationList.get(i);
			printCombination(combination);
		}
	}
	public void printWinCombinationsSize() {
		System.out.println("胜利组合个数：" + winCombinationList.size());
	}
	
	public void printDrawCombinations() {
		System.out.println("平局组合：");
		if(drawCombinationList.size() == 0) {
			System.out.println("无" + "\n");
		}
		for(int i = 0; i < drawCombinationList.size(); ++i) {
			StoneCombination combination = drawCombinationList.get(i);
			printCombination(combination);
		}
	}
	public void printDrawCombinationsSize() {
		System.out.println("平局组合个数：" + drawCombinationList.size());
	}
	
	public void printUndefeatedCombinations() {
		System.out.println("不败组合：");
		if(undefeatedCombinationList.size() == 0) {
			System.out.println("无" + "\n");
		}
		for(int i = 0; i < undefeatedCombinationList.size(); ++i) {
			StoneCombination combination = undefeatedCombinationList.get(i);
			printCombination(combination);
		}
	}
	public void printUndefeatedCombinationsSize() {
		System.out.println("不败组合个数：" + undefeatedCombinationList.size());
	}
	
	public void printOptimalUndefeatedCombinations() {
		for(Map.Entry<StoneCombination, Integer> entry : undefeatedCombinationMap.entrySet()) {
			StoneCombination c = entry.getKey();
			System.out.println();
			printCombination(c);
			System.out.println("优势次数：" + entry.getValue());
		}
	}
	
	public void printLoseCombinations() {
		System.out.println("失败组合：");
		if(loseCombinationList.size() == 0) {
			System.out.println("无" + "\n");
		}
		for(int i = 0; i < loseCombinationList.size(); ++i) {
			StoneCombination combination = loseCombinationList.get(i);
			printCombination(combination);
		}
	}
	public void printLoseCombinationsSize() {
		System.out.println("失败组合个数：" + loseCombinationList.size());
	}
	
	private void printCombination(StoneCombination combination) {
		System.out.println("攻击石：" + combination.getAttackStoneNumber() + "," + 
				   "防御石：" + combination.getDefenseStoneNumber() + "," +
				   "气血石：" + combination.getHpStoneNumber()+ " | ");
	}
	
	private void addWinCombination(StoneCombination combination) {
		if(!winCombinationList.contains(combination)) {
			winCombinationList.add(combination);
		}
	}
	private void addDrawCombination(StoneCombination combination) {
		if(!drawCombinationList.contains(combination)) {
			drawCombinationList.add(combination);
		}
	}
	private void addUndefeatedCombination(StoneCombination combination) {
		if(!undefeatedCombinationList.contains(combination)) {
			undefeatedCombinationList.add(combination);
		}
	}
	private void addLoseCombination(StoneCombination combination) {
		if(!loseCombinationList.contains(combination)) {
			loseCombinationList.add(combination);
		}
	}

	public void setPlayerLevel(int playerLevel) {
		this.playerLevel = playerLevel;
	}

	public int getPlayerLevel() {
		return playerLevel;
	}

	public void setStoneLevel(int stoneLevel) {
		this.stoneLevel = stoneLevel;
	}

	public int getStoneLevel() {
		return stoneLevel;
	}
	
	private void increaseCombinationNumber(StoneCombination stoneCombination) {
		Integer number = undefeatedCombinationMap.get(stoneCombination);
		if(number == null)
			number = new Integer(0);
		number++;
		undefeatedCombinationMap.put(stoneCombination, number);
	}
}
